Deep-Emotive é um protótipo para reconhecer e classificar as expressões faciais das emoções, alegria, desgosto, medo, raiva, surpresa, tristeza, consideradas por Ekman et al. (1987), como básicas e universais, utilizando técnicas já consolidadas das áreas de Processamento Digital de Imagem e Visão Computacional. Estas técnicas são combinadas com uma nova abordagem, considerada a mais avançada no reconhecimento visual de objetos através do aprendizado de máquina, o Aprendizado Profundo ou Deep Learning.
O trabalho desenvolvido implementou um classificador de emoções capaz de reconhecer oito emoções, alcançando 96,33%. As duas emoções reconhecidas e que não estavam na proposta inicial são desprezo e neutra.
Adicionalmente, foi implementada a técnica de Transferência de Aprendizado, com o objetivo de validar o aprendizado obtido pelo classificador de emoções proposto, bem como para investigar suas limitações. Foi utilizado para esta técnica as bases de dados:
Os resultados obtidos foram satisfatórios quando aplicado a transferência de aprendizado na base de dados JAFFE, atingindo uma precisão de 93,02%. No entanto o protótipo apresentou baixa assertividade, alcançado 60,62% de precisão na base de dados FER-2013. Uma das razões da baixa assertividade é que a base de dados FER-2013 possui imagens dissimilares às bases de dados citadas anteriormente, contendo imagens com problemas que ainda são desafiadores para a área de visão computacional, como oclusão e ruido. No entanto, o resultado foi superior à taxa de escolha randômica de 50%.
# Bibliotecas necessárias para execução do módulo de detecção da face
import random
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from IPython.display import display
import pandas as pd
import itertools
from IPython.display import display, HTML
# Modulo para trabalhar com de coleções em forma de dicionarios
from collections import OrderedDict
# Referência: http://scikit-learn.org/stable/auto_examples/model_selection/plot_confusion_matrix.html
from mpl_toolkits.axes_grid1 import make_axes_locatable
# biblioteca para trabalhar com imagens
from PIL import Image, ImageEnhance
# Scikitlearn
from sklearn.utils import shuffle
#from sklearn.cross_validation import train_test_split #cross_validation is deprecated
# Configunrando o framework Keras.
# Importando o modelo do Keras (https://keras.io/getting-started/sequential-model-guide/)
from keras.models import Sequential
# Importando modelo para salvar e importar a DNN
from keras.models import model_from_json, load_model
# Importando o tipo de camada
from keras.layers import Input,Dense
from keras.layers import merge
# Importando modulo de Dropout da rede, para aplicar mutações.
from keras.layers import Dropout
# Importando modulo de achatamento dos vetores.
# Aprimora a entrada. Não afeta o tamanho do lote.
# (https://keras.io/layers/core/#flatten)
from keras.layers import Flatten
# Importando modulo para explrar as camadas do modelo
from keras.models import Model
# Importanto modulo de convolução (https://keras.io/layers/convolutional/)
from keras.layers.convolutional import Conv2D
# Importando modulo para trabalhar com as bordas da imagem (https://keras.io/layers/convolutional/#zeropadding2d)
from keras.layers.convolutional import ZeroPadding2D
# Importando modulo para normalizar a imagem (https://keras.io/layers/convolutional/#zeropadding2d)
from keras.layers.normalization import BatchNormalization
# Importando modulo de subamostragem (https://keras.io/layers/pooling/)
from keras.layers.convolutional import MaxPooling2D
from keras.layers.pooling import AveragePooling2D
# Importando Lib de utilidades (https://keras.io/utils/)
from keras.utils import np_utils
# Importante modulo de trabalho em backend (Th ou Tf) (https://keras.io/backend/)
from keras import backend as K
# modulo para trabalhar reprocessar as imagens
from keras.preprocessing import image
# modulo de utilizades para trabalhar reprocessar as imagens
from keras.utils.data_utils import get_file
# modulo de callback para parar o treinamento na melhor opção
from keras.callbacks import EarlyStopping, ModelCheckpoint
# fine tunnig
from keras import optimizers
# ativadores avançados
from keras.layers.advanced_activations import LeakyReLU, PReLU
# Modulo Scikit-Learn para montar a matriz de confusão
from sklearn.metrics import classification_report, confusion_matrix, precision_score, recall_score, f1_score, cohen_kappa_score
#import theano
#import keras_mnist_vis
#K.set_image_dim_ordering('th')
# permitindo mais de um print por saÃda
from __future__ import print_function
# para criação do dataset em x_train, x teste
from sklearn.model_selection import train_test_split
# modulo do sistema operacional
import os
import platform
print('Python version:',platform.python_version())
# Dimensões da imagem
# img_rows, img_cols = 640, 490 <--- TAMANHO NORMAL
img_rows, img_cols = 98, 98 #<--- # TESTES
#img_rows, img_cols = 224, 224 #<--- # TESTES
#img_rows, img_cols = 80, 60 # TESTES
# números de canais(RGB)
img_channels = 1
# Configurando o plot para ser inline ao inves de outra janela.
%matplotlib inline
plt.rcParams['figure.figsize'] = (10.0, 8.0) # padronizando tamanho plot
plt.rcParams['image.interpolation'] = 'nearest'
#plt.rcParams['image.cmap'] = 'gray' # padronizndo color map
%load_ext autoreload
%autoreload 2
A fase de pré-processamento é responsável pela aplicação de transformações nas imagens importadas para o protótipo, redimensionando cada imagem para uma dimensão prédefinida de 98 pixels largura e 98 pixels de altura. Para esta fase existe a possibilidade de ser aplicada a técnica Data Augmentation, ativada através do flag dataAugmentation, com a finalidade de aumentar o conjunto de dados original, porém sua utilização é opcional
# diretorio database imagens
path = './faces' #path of folder to save images
# listando a quantidade de pastas no diretório imagens
# Os diretórios dão origem as classes = ['alegria', 'desgosto', 'desprezo', 'medo', 'neutral', 'raiva', 'surpresa', 'tristeza']
classes_emocoes = os.listdir(path)
num_emocoes = len(classes_emocoes)
print("Quantidade de emoções: ",num_emocoes)
print(classes_emocoes)
def _rotacionar_imagem(imagem):
""" Esta função é responsável por criar transformações de rotação na imagem.
Recebe como entrada uma objeto de imagem python e retorna uma lista
com quatro objetos de imagens python com as variações de rotação
em -30°, -15°, 15° e 30° graus.
Args:
imagem (PIL): objeto de imagem python.
Returns:
list: lista com quatro objetos de imagens python.
"""
novas = [] # para salvar novas amostras
im1 = imagem.copy() # cria cópia da imagem original
novas.append(im1.rotate(-30, resample=Image.BICUBIC)) # aplica rotação em - 30° e salva
im2 = imagem.copy()
novas.append(im2.rotate(-15, resample=Image.BICUBIC)) # aplica rotação em - 15° e salva
im3 = imagem.copy()
novas.append(im3.rotate(30, resample=Image.BICUBIC)) # aplica rotação em 30° e salva
im4 = imagem.copy()
novas.append(im4.rotate(15, resample=Image.BICUBIC)) # aplica rotação em 15° e salva
return novas
def _corrigir_brilho_imagem(imagem):
""" Esta função é responsável por criar transformações de brilho na imagem.
Recebe como entrada uma objeto de imagem python e retorna um novo
objeto de imagem python aprimorado.
Args:
imagem (PIL): objeto de imagem python.
Returns:
imagem (PIL): objeto de imagem python aprimorado.
"""
imagem_aprimorada = imagem.copy() # cria uma cópia da imagem original
ImageEnhance.Brightness(imagem_aprimorada) # aplica a correção de brilho.
return imagem_aprimorada
def carregar_imagens(path):
""" Esta função é responsável por importar as imagens para
o protótipo. Recebe caminho do diretório onde as imagens
estão localizadas. Retorna uma lista de tuplas de duas
posições. A primeira posição é o objeto de imagem e a
segunda é a emoção da imagem.
Args:
path (string): caminho do diretório onde as imagens
estão localizadas.
Returns:
tuple (len=2): tupla contendo objeto imagem e emoção.
"""
imagens = [] # lista para guardar as faces segmentadas
classes_emocoes = os.listdir(path)
# para cada categoria(emoção)
for emocao in range(len(classes_emocoes)):
m_path = os.path.join(path, classes_emocoes[emocao]) # path src
# pega todos os arquivos da emocao
files = [f for f in os.listdir(m_path)]
print('Carregando imagens de {}, qtd: {}...'.format(
classes_emocoes[emocao], len(files)))
for file in files: # para cada imagem
path_img = m_path + '\\' + file #caminho absoluto
im = Image.open(path_img) # obj PIL
imagens.append((im, emocao)) # insere face an lista
print('Imagens carregadas com sucesso!')
print('Quantidade de imagens: ',len(imagens))
return imagens
# Carregando imagens e sua classificação.
#imagens = carregar_faces(path ,dataAugmentation=True)
imagens = carregar_imagens(path)
# verificando qunatidade de imagens para trabalhar
qtd_imagens = len(imagens) # get the number of images
print('Quantidade de imagens para trabalhar: ',qtd_imagens)
# iniciando acesso as imagens
# como esta repersentado a imagem = tupla(imagem, categoria)
print('Representação da lista de imagem: ',imagens[0])
# Verificando a distribuição da base de dados
# [0='alegria', ' 1= desgosto', '2= desprezo', '3= medo','4 = neutral', '5= raiva', '6= surpresa', '7= tristeza']
def qtd_por_emocao(imagens):
alegria = [x for x in imagens if x[1] == 0]
desgosto = [x for x in imagens if x[1] == 1]
desprezo = [x for x in imagens if x[1] == 2]
medo = [x for x in imagens if x[1] == 3]
neutral = [x for x in imagens if x[1] == 4]
raiva = [x for x in imagens if x[1] == 5]
surpresa = [x for x in imagens if x[1] == 6]
tristeza = [x for x in imagens if x[1] == 7]
print("Alegria:",len(alegria), "- Desgosto:",len(desgosto), "- Desprezo:",len(desprezo), "- Medo:",len(medo), "- Neutra:",len(neutral), "- Raiva:",len(raiva), "- Surpresa:",len(surpresa), "- Tristeza:",len(tristeza))
return len(alegria), len(desgosto), len(desprezo), len(medo), len(neutral), len(raiva), len(surpresa), len(tristeza)
# Visualizando a distribuição por categoria de emoção
def visualiza_distribuicao(imagens):
dist_y = qtd_por_emocao(imagens)
dist_x = np.arange(num_emocoes)
x_label = classes_emocoes
fig,ax = plt.subplots(figsize=(4,4))
ax.bar(dist_x, dist_y, width=0.8, color='blue')
ax.set_xticks(dist_x)
ax.set_xticklabels(x_label, rotation=90)
plt.show()
visualiza_distribuicao(imagens)
x, y = np.arange(num_emocoes), qtd_por_emocao(imagens)
def pre_processamento_imagens(imagens, img_size=(img_rows,img_cols), dataAugmentation=True):
""" Esta função é responsável por aplicar transformações
na imagem. O primeiro parametro aplica transformações
de redimensionamento e convete a imagem para escala
cinza. O segundo aplica transformações de correção
de brilo e rotação. Este segundo implica no aumento
do conjunto de dados em 600%
Args:
imagens (PIL): lista de tuplas (imagens, emocao).
dataAugmentation (boolean): flag para aplicar rotações
na imagem.
Returns:
list: retorna uma lista de tuplas (imagem, emocao)
"""
_imagens =[]
print('Pre-processamento das imagens...')
for (imagem, emocao) in imagens:
# reduz a dimensão da imagem o tamanho 98x98
imagem = imagem.resize(img_size, Image.ANTIALIAS)
img_cinza = imagem.convert('L') # escala de cinza.
# salva o objeto (imagem,emocao)
_imagens.append((img_cinza, emocao))
if dataAugmentation: # Aumentando a base de dados
imagens_rotacionadas = _rotacionar_imagem(img_cinza) # aplicando rotação
for img in imagens_rotacionadas: # para cada nova imagem
_imagens.append((img, emocao)) # salva nova imagem na lista padrão
imagem_brilho = _corrigir_brilho_imagem(img_cinza) # aplicando brilho
_imagens.append((imagem_brilho, emocao))
print('Pre-processamneto das imagens concluido com sucesso!')
return _imagens
imagens_processadas = pre_processamento_imagens(imagens)
# verificando qunatidade de imagens para trabalhar
qtd_imagens = len(imagens_processadas) # get the number of images
print('Quantidade de imagens para trabalhar: ',qtd_imagens)
# iniciando acesso as imagens
# como esta repersentado a imagem = tupla(imagem, categoria)
print('Representação da lista de imagem: ',imagens[0])
visualiza_distribuicao(imagens_processadas)
x, y2 = np.arange(num_emocoes), qtd_por_emocao(imagens_processadas)
diff = np.array(y2) - np.array(y)
diff
plt.figure(figsize=(6,5))
p1 = plt.bar(x, y, 0.8, color='#d62728')
p2 = plt.bar(x, diff, 0.8,bottom= y)
plt.ylabel('quantidade')
x_label = classes_emocoes
plt.xticks(x, x_label, rotation=90)
plt.legend((p1[0], p2[0]), ('Original', 'Data Augmentation'))
plt.show()
imagens = []
imagens = imagens_processadas
#visualiza_distribuicao(imagens)
A etapa preparar dados, é responsável por preparar o conjunto de dados para o treinamento, para que seja possÃvel sua utilização pelo framework de aprendizado profundo.
# Seleciona uma imagem aleatoria
idx_img_aleatoria = random.randint(0, qtd_imagens)
img_aleatoria, emocao_aleatoria = imagens[idx_img_aleatoria][0], imagens[idx_img_aleatoria][1]
#print(img_aleatoria.size)
print("Formato da imagem: {}".format(np.array(img_aleatoria).T.shape))
print("Emocão da imagem: {}".format(classes_emocoes[emocao_aleatoria]))
# Visualizar a imagem aleatoria
plt.figure(figsize=(6,6))
plt.imshow(img_aleatoria, cmap='gray')
#plt.axis('off')
def _get_pixels_imagem(imagem, shape=(img_cols,img_rows)):
""" Esta função é responsável por extrair os pixels
da imagem. Recebe como entrada uma objeto de imagem
python e retorna um numpy array contendo uma
lista de lista de todos os pixels. Pode ser
alterado a dimensão da imagem pelo parametro shape.
Args:
imagem (PIL): objeto de imagem python.
shape (tuple): tupla contendo o dimensão
da imagem de saida.
Returns:
array (np.ndarray): retorna um array numpy.
"""
# cria uma array numpy com uma lista contendo
# todos os pixels da imagem
pixel_values = np.array(list(imagem.getdata()))
# redimensiona os pixels para formato 98x98
pixel_values = pixel_values.reshape(shape)
return pixel_values
#Conferindo a extração dos pixels e remomtando a imagem
array_pixels = _get_pixels_imagem(img_aleatoria)
print("Formato da array de pixels: {}".format((array_pixels.shape)))
print("Emocão da imagem: {}".format(classes_emocoes[emocao_aleatoria]))
plt.figure(figsize=(6,6))
plt.imshow(array_pixels, cmap='gray')
# extrair os pixels das imagems
def extrair_dados(imagens):
""" Esta função é responsável por extrair os pixels de
todas as imagem da base de dados.
Recebe como entrada uma lista de objeto de
imagem python e retorna uma lista de
numpy.ndarray contendo todos os pixels
de todas as imagens.
Args:
imagens (list): lista objeto de imagem python.
Returns:
array (np.ndarray): retorna uma array numpay.
"""
data = [] # para armazenar os dados
array_emocoes = [] # para armazenar os descritores
print("Extraindo os dados...")
# para cada imagem
for imagem in range(len(imagens)):
# extrai o array de pixels da imagem
data.append(_get_pixels_imagem(imagens[imagem][0]))
# extrai a emocao que já estava definida na tupla
array_emocoes.append(imagens[imagem][1])
print("Quantidade de imagens extraidas:",len(data))
print("Quantidade de emocoes extraidas:",len(array_emocoes))
print("Extração de pixels completa!")
return data, array_emocoes
# empilhar dados para trabalhar com o framework
data, array_emocoes = extrair_dados(imagens)
# Função que empilha o conjunto de dados,
# em formato de tupla para trabalhar com o deep learning
def empilhar_dados(dados):
""" Esta função é responsável por empilhar os dados
para o formato que exigido para trabalho com o
framework Keras. Recebe como entrada lista de
dados e retorna uma tupla contendo a
quantidade de dados, dimensão x, e dimensão y.
Args:
dados (list): lista de dados.
Returns:
tuple: retorna uma tupla com
(quantidade, largura, altura).
"""
print("Empilhando conjunto de dados:(quantidade, largura, altura)...")
# faz uso da fucionalidade numpy de empilhamento
dados_empilhados = np.stack(dados)
print("novo formato dos dados:", dados_empilhados.shape)
return dados_empilhados
# empilhar imagens
print('Empilhando imagens...')
data = empilhar_dados(data)
print('Empilhando descritores de emoção...')
# empilhar descritores de emoção
labels = empilhar_dados(array_emocoes)
print("Fase de empilhamento completa!")
# Conferindo os pixels da imagem a partir dos dados estraidos.
print("Formato dos dados: {}".format(data[0].shape))
display(pd.DataFrame(data[0]))
# Visualizando uma imagem a partir dos dados extraidos
# Seleciona um indice
idx_img_aleatoria = random.randint(0, data.shape[0])
print("Indice da imagem: ", idx_img_aleatoria)
# seleciona uma imagem
img_aleatoria = data[idx_img_aleatoria]
print("Formato do imagem: {}".format(img_aleatoria.shape))
print("Emocão da imagem: {}".format(classes_emocoes[labels[idx_img_aleatoria]]))
plt.figure(figsize=(6,6))
plt.imshow(img_aleatoria, cmap='gray')
# organizando dados para trabalhar com o keras
(X, y) = (data, labels)
# backup para plot na predição
print('Criando backup dos dados...')
X_test_orig = X
Y_test_orig = y
print('Backup - Estrutura do dados: ',X_test_orig.shape)
print('Backup - labels: ',len(Y_test_orig))
print('Backup completo!')
def amostragem(quantidade, limite):
fig = plt.figure(figsize=(16,16))
for i in range(quantidade):
idx = random.randint(0,limite-1),
input_img = X_test_orig[idx[0]].reshape(img_cols, img_rows)
ax = fig.add_subplot(10,10,i+1)
ax.imshow(input_img, interpolation='nearest', cmap='gray')
idx_emocao = idx[0]
plt.text(0, 0, classes_emocoes[Y_test_orig[idx_emocao]], color='black',
bbox=dict(facecolor='white', alpha=1),fontsize=20)
plt.xticks(np.array([]))
plt.yticks(np.array([]))
plt.tight_layout()
plt.show()
# Visualizando amostra dos dados
amostra = 30
amostragem(amostra, len(X_test_orig))
# Separando os dados para treinamento
def separar_treino_e_teste(imagens, descritores):
""" Esta função é responsável por separa os dados
em conjunto de treino e teste. Recebe como
entrada tupla contendo todos os dados da
imagens e uma tupla contendo os descritores.
Retorna uma tupla contendo imagens de treino,
descritores de treino, imagens de teste e
descritores de teste.
Args:
imagens (tuple): tupla de dados .
Returns:
tuple: tupla contendo dados de treino, dados de teste.
"""
# test_size=0.2 = percentual de separação 20% para teste
# random_state = definindo a semente para escolha aleatoria
print('Separando os dados em grupo de treino e teste...')
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.2, random_state= int(qtd_imagens))
print('Imagens separadas para treino: ',X_train.shape)
print('Imagens separadas para teste: ',X_test.shape)
print('Emoções separadas para treino: ',y_train.shape)
print('Emoções separadas para teste: ',y_test.shape)
return X_train, X_test, y_train, y_test
X_train, X_test, y_train, y_test = separar_treino_e_teste(X, y)
# configura shape, adicionando a camanda de cor
# Shape é configurado de acordo com framework de background: tensorflow(tf) ou Theano(th)
def formatar_shape(X_train, X_test, canais=1):
""" Esta função é responsável por formatar os dados
para trabalhar com o deep learning, de acordo com
o framework que está em background (tensorflow(tf)
ou Theano(th)).
Recebe como parametro a quantidade de canais de cor
que as imagens possuem.
Args:
X_train (tuple): imagens de treinamento
X_train (tuple): imagens de teste
canais (int): quantidade de canais de profundidade.
Returns:
tuple: tupla contendo dados de treino, dados de teste,
e o shape dos dados, formatados para deep learning.
"""
print("Adicionando canais de cores na estrutura de dados...")
# O framework theano trabalha com a quantidade de canais
# de cores a frente da dimesão da imagem
if K.image_data_format() == 'channels_first': # = th
shape = (canais, img_cols, img_rows)
#shape = (1, img_cols, img_rows)
print("Trabalhando com theano:", shape)
# O framework tensorflow trabalha com a quantidade de canais
# de cores apos a dimesão da imagem
else: # channel_last = tf
shape = (img_cols, img_rows, canais)
#shape = (img_cols, img_rows, 1)
print("Trabalhando com tensorflow:",shape)
print("Novo formato para estrutura de dados contendo o canal de cor: ",shape)
print('Alterando o formato das imagens, colocando a estrutura com canal de cor...')
X_train = X_train.reshape((X_train.shape[0],) + shape).astype('float32')
X_test = X_test.reshape((X_test.shape[0],) + shape).astype('float32')
print('Novo formato das imagens separadas para treino: ',X_train.shape)
print('Novo formato das imagens separadas para teste: ',X_test.shape)
# cada pixels é normalizado = pixel = pixel / 255
print('Normalizando os dados...')
X_train /= 255
X_test /= 255
return X_train, X_test, shape
X_train, X_test, shape = formatar_shape(X_train, X_test)
# Definindo a qunatidade de neurõnios por camada da DNN
# quantidade de pixels na camada de entrada de dados
# um neuronio para cada pixel
num_pixels = X_train.shape[1] * X_train.shape[2]
print("Quantidade de neurônios (camada entrada): ",num_pixels)
# Criando a classificação
# Converte um vetor de classe (inteiros) em matriz de classe verdade (binária).
def criar_matriz_verdade(y_train, y_test):
""" Esta função é responsável por criar uma matriz
verdade para todos os descritores do conjunto de dados.
Recebe como parametro os descritores de treino e teste.
Args:
Y_train (tuple): descritores de emoção de treinamento
Y_test (tuple): descritores de emoção de teste
Returns:
tuple: tupla contendo as matrizes verdade dos
descritores de treino, dados de teste,
"""
print('Criando a matriz de classificação binária...')
# Classificando os descritores de treino
Y_train = np_utils.to_categorical(y_train)
# Classificando os descritores de teste
Y_test = np_utils.to_categorical(y_test)
# verificando a quantidade de classes encontradas
n_treino = Y_train.shape[1]
print('Classes encontradas para imagens: ', n_treino)
# verificando a quantidade de classes encontradas
n__teste = Y_test.shape[1]
print('Classes encontradas para emocoes: ', n__teste)
return Y_train, Y_test
Y_train, Y_test = criar_matriz_verdade(y_train, y_test)
# visualizando matriz verdade
print(Y_train[:5])
print(Y_train.shape)
print(Y_test[:5])
print(Y_test.shape)
Nesta etapa do desenvolvimento é criado a arquitetura da rede neural utilizando as técnicas de aprendizado profundo. Para este trabalho, será utilizado o modelo de redes neurais convolucionais. A rede neural profunda, utilizada neste protótipo, foi definida após inúmeras tentativas descritas na seção de experimentos, e possui a arquitetura ilustrada na figura abaixo.
display(HTML('''<img src="./util/Diagrama - Arquitetura da rede neural -FINAL.png">'''))
# Criando arquitetura da rede DNN
def criar_deep_cnn_10(num_classes, shape):
""" Esta função é responsável por criar a rede neural convulocional.
Recebe como parametro a quantidade de categorias a serem
classificadas pela rede, e o formato de entrada dos dados.
Args:
num_classes (int): quantidade de categorias a serem classificadas
shape (tuple): formato de entrada dos dados.
Returns:
model: rede neural profunda completa.
"""
nucleos_conv1 = 64 # Quantidade de núcleos (Campos receptivos locais)
nucleos_conv2 = 128 # Quantidade de núcleos (Campos receptivos locais)
nucleos_conv3 = 256 # Quantidade de núcleos (Campos receptivos locais)
dropout_1 = 0.25 # Dropout para emitar overffiting = 25%
dropout_2 = 0.5 # Dropout para emitar overffiting = 50%
neuronios_camada_densa = 512 # quantidade de neuronios escondidos para a camada densa
campos_receptivos_nucleos = (5, 5) # tamanho do nucleo de convolucao
campos_receptivos_pooling = (2, 2) # tamanho do nucleo de pooling
# tipo keras senquencial (https://keras.io/getting-started/sequential-model-guide/)
model = Sequential()
# [INICIO - Primeira bloco de convolução]
# Adicionando uma camada de convolução (Convolution2D - com esparsividade) para entrada de dados.
# Camada ConvNet terá 64 núcleos (campos receptivos de 5 x 5 pixels).
# Padding = same, o tamanho da saÃda será igual ao tamanho da entrada: input=(98,98) -> output=(98,98)
# Por default a rede CONV2D já utiliza bias=True e os inicializa com 0
# Por default o tamanho do passo é 1 pixel, stride=(1,1)
model.add(Conv2D(nucleos_conv1, campos_receptivos_nucleos, input_shape=shape, padding='same', name='Bl01_Conv'))
# Adicionado uma camada para função de ativação do neurônio, função PRelu (https://arxiv.org/abs/1502.01852)
model.add(PReLU(name='Bl01_PReLU'))
# Adicionando uma camada de subamostragem (AveragePooling2D).
# Esta camada reduz pela metade as dimensões da imagem, ou seja, input=(98,98) -> output=(49, 49)
model.add(AveragePooling2D(pool_size=(campos_receptivos_pooling), name='Bl01_Pooling'))
# [FIM - Primeiro bloco convolucional]
# [INICIO - Segundo bloco convolucional]
# Camada ConvNet terá 128 núcleos (campos receptivos de 5 x 5 pixels).
# Arranjo espacial com apenas 1 canal de cor e imagem com dimesão (49, 49)
# Padding = valid, o tamanho da saÃda será menor ao tamanho da entrada: input=(49, 49) -> output=(45, 45)=(Size-nucleo+1)
model.add(Conv2D(nucleos_conv2, campos_receptivos_nucleos, name='Bl02_Conv'))
# Adicionado uma camada para função de ativação do neurônio, função PRelu (https://arxiv.org/abs/1502.01852)
model.add(PReLU(name='Bl02_PRelu'))
# Adicionando uma camada de subamostragem (AveragePooling2D).
# Esta camada reduz pela metade as dimensões da imagem, ou seja, input=(45,45) -> output=(22, 22)
model.add(AveragePooling2D(pool_size=campos_receptivos_pooling, name='Bl02_Pooling'))
# [FIM - Segundo bloco convolucional]
# [INICIO - Terceiro bloco convolucional]
# Camada ConvNet terá 256 núcleos (campos receptivos de 5 x 5 pixels).
# Padding = valid, o tamanho da saÃda será menor ao tamanho da entrada: input=(22, 22) -> output=(18, 18)=(Size-nucleo+1)
# Esta camada reduz pela metade as dimensões da imagem, ou seja, input=(18, 18) -> output=(9, 9)
model.add(Conv2D(nucleos_conv3, campos_receptivos_nucleos, name='Bl03_Conv'))
# Adicionado uma camada para função de ativação do neurônio, função PRelu (https://arxiv.org/abs/1502.01852)
model.add(PReLU(name='Bl03_PRelu'))
# Adicionando uma camada de subamostragem (AveragePooling2D).
model.add(AveragePooling2D(pool_size=campos_receptivos_pooling, name='Bl03_Pooling'))
# [FIM - Terceiro bloco convolucional]
# [INICIO - Interligação da rede convolucional para rede totalmente conectada]
# adiciona uma camada de dropout, para evitar overfitting
# Não altera as dimensões da imagem
model.add(Dropout(dropout_1, name='Dropout1'))
# Achata o vetor
# Não altera as dimensões da imagem
# Tranforma uma imagem de input=(9, 9) e com 256 núcleos, em um vetor de 20.736 posições=(9*9*256)
model.add(Flatten(name='Ligacao'))
# [FIM - Interligação de rede convolucional para rede totalmente conectada]
# [INICIO - Primeiro bloco de rede totalmente conectada]
# Adicionando primeira camada densa (totalmente conectada), destinada a classificação.
# Possui input=(20.736) e saÃda de 512 neurônios.
# Não altera as dimensões da imagem
model.add(Dense(neuronios_camada_densa, name='Classi_Densa1'))
# Adicionado uma camada para função de ativação do neurônio, função PRelu (https://arxiv.org/abs/1502.01852)
model.add(PReLU(name='Classi_PRelu'))
# [FIM - primeiro bloco de rede totalmente conectada]
# [INICIO - Interligação dos blocos de rede totalmente conectados]
# adiciona uma camada de dropout, para evitar overfitting
# Não altera as dimensões da imagem
model.add(Dropout(dropout_2, name='Dropout2'))
# [FIM - Interligação dos blocos de rede totalmente conectados]
# [INICIO - Segundo bloco de rede totalmente conectada]
# Adicionando segunda camada densa (totalmente conectada) para saÃda de dados
# Possui input=(512) e saÃda de 8 neurônios.
# Os 8 neurônios são a classificação para as 8 emoções
# Função de ativação do neurônio será Softmax (https://en.wikipedia.org/wiki/Softmax_function)
model.add(Dense(num_classes, activation='softmax',name='Classi_Densa2'))
#model.compile(loss = 'categorical_crossentropy', optimizer = 'rmsprop', metrics = ['accuracy']) = #time: 2h 9min 4s=83.85%
#model.compile(loss = 'categorical_crossentropy', optimizer = 'adam', metrics = ['accuracy']) = 2h 1min 50s=81.65%
#model.compile(loss = 'categorical_crossentropy', optimizer = 'sgd', metrics = ['accuracy']) = time: 2h 4min 50s=27.89%
#model.compile(loss = 'categorical_crossentropy', optimizer = 'adagrad', metrics = ['accuracy']) =time: 2h 5min 25s= 35.96%
#model.compile(loss = 'categorical_crossentropy', optimizer = 'adadelta', metrics = ['accuracy']) =
#model.compile(loss = 'categorical_crossentropy', optimizer = 'adamax', metrics = ['accuracy']) =
#model.compile(loss = 'categorical_crossentropy', optimizer = 'nadam', metrics = ['accuracy'])
#Prelu = 2h 27min 59s + 2h 25min 39s + 2h 25min 49s + 2h 33min 18s + 7h 16min 59s= 86.42%
# Função para otimização estocástica, requer apenas gradientes de primeira ordem com pouco requisito de memória.
# Referência: (KINGMA, Diederik; BA, Jimmy. Adam: A method for stochastic optimization. arXiv preprint arXiv:1412.6980, 2014.)
# lr: taxa de aprendizado
# decay: tamanho do passo da caÃda do gradiente
adam = optimizers.Adam(lr=1e-3, decay=1e-5)
# Copilando o modelo
# Função de apredizado será cross-entropy (https://en.wikipedia.org/wiki/Cross_entropy)
# métrica de reconhecimento será precisão.
model.compile(loss = 'categorical_crossentropy', optimizer = adam, metrics = ['accuracy'])
return model
# Compilando o modelo proposto
model = criar_deep_cnn_10(num_emocoes, shape)
# visualizando o modelo criado
model.summary()
# Verificando o arranjo espacial do modelo
for i, layer in enumerate(model.layers):
print ("Camada", i, "\t", layer.name.strip(),"\t\t", layer.input_shape, "\t", layer.output_shape)
Nesta seção é apresentado a etapa de treinamento da rede neural profunda. Cada imagem do conjunto de dados de treino é convoluÃda através da rede neutral profunda. É realizado a extração das caracterÃsticas em cada bloco de convolução e atualizado os pesos do treinamento.
# monitor para ouvir e parar o treinamento caso o aprendizado comece a cair
monitor = EarlyStopping(monitor='val_loss', min_delta=1e-4, patience=5, verbose=1, mode='auto')
# chekpoint para salvar o mehlor aprendizado enter as epocas
filepath="pesos_teste_10-{epoch:02d}-{val_acc:.2f}.hdf5"
checkpoint = ModelCheckpoint(filepath, # caminho para o modelo salvo
monitor= 'val_acc', # qual parametro vai acompanhar
verbose=0, # verbosity - 0 or 1
save_best_only= True, # sobreescreve o modelo apenas se for o melhor
mode='auto') # dependecia de acorco com o monitor
#callback_list=[monitor, checkpoint]
callback_list=[checkpoint]
def treinar_rede_deep_cnn(model, X_train, Y_train,
X_test, Y_test, epocas=20, batch=99, callback_list = None):
""" Esta função é responsável por realizar o treinamento
da rede neural convolucional profunda.
Recebe como parâmetro o modelo da rede, a quantidade de
epocas de treinamento, e o tamanho do lote de treinamento.
Args:
model (sequencial): modelo da rede neural
X_train (array): imagens de treino.
Y_train (array): descritores de treino.
X_teste (array): imagens de teste.
Y_teste (array): descritores de teste.
epocas (int): quantidade de epocas de treinamento
batch (int): tamanho do lote de treinamento.
Returns:
history: log's do aprendizado da rede
model: rede neural profunda completa.
"""
print('Treinando a rede neural profunda...')
# % time: contador do tempo de processamento
%time history = model.fit(X_train,Y_train,validation_data=(X_test, Y_test), callbacks=callback_list, epochs= epocas,batch_size= batch,verbose=1)
print('Treinanmeto finalizado!')
return history, model
history, model = treinar_rede_deep_cnn(model, X_train, Y_train, X_test, Y_test, epocas=20, batch=99, callback_list)
# Avaliando o modelo RNA
print('Metricas do Modelo: {}'.format(model.metrics_names))
metricas = model.evaluate(X_test, Y_test, verbose=1)
print("Erro de: %.2f%%" % (100-metricas[1]*100))
print("Precisão de: %.2f%%" % (metricas[1]*100))
Este gráfico ilustra a precisão do treinamento e do teste, assim como a taxa de erro, para cada interação realizada pela rede.
def plot_model(history):
# Cria subplots
fig, axs = plt.subplots(1,2,figsize=(15,5))
# Precisão
axs[0].plot(range(1,len(history.history['acc'])+1),history.history['acc'])
axs[0].plot(range(1,len(history.history['val_acc'])+1),history.history['val_acc'])
axs[0].set_title('Precisão da DNN')
axs[0].set_ylabel('Precisão')
axs[0].set_xlabel('Época')
axs[0].set_xticks(np.arange(1,len(history.history['acc'])+1),len(history.history['acc'])/10)
axs[0].legend(['treino', 'validação'], loc='best')
# Perda
axs[1].plot(range(1,len(history.history['loss'])+1),history.history['loss'])
axs[1].plot(range(1,len(history.history['val_loss'])+1),history.history['val_loss'])
axs[1].set_title('Perda da DNN')
axs[1].set_ylabel('Perda')
axs[1].set_xlabel('Época')
axs[1].set_xticks(np.arange(1,len(history.history['loss'])+1),len(history.history['loss'])/10)
axs[1].legend(['treino', 'validação'], loc='best')
# Visualizar
plt.show()
plot_model(history)
Esta etapa salva a arquitetura criada para uso posterior. É salvo no formato .json
# Salvando o modelo criado
print('Salvando o modelo...')
# serialize model para formato JSON
MODELO_SALVO_JSON = 'deep_emotive_model_t10_faces.json'
model_json = model.to_json()
with open(MODELO_SALVO_JSON, "w") as json_file:
json_file.write(model_json)
print('Modelo salvo com sucesso!')
# Treinando o modelo DNN para 01 época
# Função FIT: realiza o treinamento até uma quantidade de épocas determinada.
# parametro validation_data: Dados para avaliar a perda do gradiente ao final de cada época
# parametro batch_size: numero de amostras para atualizar a perda do gradientes
# Paramentro verbose : 0 = silent, 1 = verbose, 2 = one log line per epoch.
# %time = medindo tempo do treino
PESOS_SALVOS = 'pesos_teste_10-265-0.96.1.hdf5'
# Flag True ou false para retreinar a rede
if True and os.path.exists(PESOS_SALVOS):
print('Carregando pesos salvos de treino anterior...')
model.load_weights(PESOS_SALVOS)
print('Pesos carregados com sucesso!')
else:
# treinando a DNN para 20 épocas
#callback_list=[monitor,checkpoint]
callback_list=[checkpoint]
print('Treinando a DNN...')
%time history = model.fit(X_train, Y_train, validation_data=(X_test, Y_test), callbacks=callback_list, epochs=350, batch_size=99, verbose=1)
print('Treinanmeto finalizado!')
# Carregando o modelo salvo
# Lendo o modelo salvo em arquivo para um novo modelo
MODELO_SALVO_JSON = 'deep_emotive_model_t10_faces.json'
print("Carregando o modelo...")
json_file = open(MODELO_SALVO_JSON, 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
print('Modelo carregado com sucesso!')
# Carregando o melhor pesos do checkout para para o novo modelo
MELHOR_PESO = './pesos/pesos_teste_10-266-0.96.3.hdf5'
print("Carregando os melhores pesos...")
loaded_model.load_weights(MELHOR_PESO)
# Compilando o modelo que estava salvo
# lr: taxa de aprendizado
# decay: tamanho do passo da caÃda do gradiente
adam = optimizers.Adam(lr=1e-3, decay=1e-5)
# Copilando o modelo
# Função de apredizado será cross-entropy (https://en.wikipedia.org/wiki/Cross_entropy)
# métrica de reconhecimento será precisão.
loaded_model.compile(loss = 'categorical_crossentropy', optimizer = adam, metrics = ['accuracy'])
print("Carregamento dos melhores pesos completo!")
loaded_model.summary()
# Avaliando o modelo RNA
print('Metricas do Modelo: {}'.format(loaded_model.metrics_names))
metricas = loaded_model.evaluate(X_test, Y_test, verbose=1)
print("Erro de: %.2f%%" % (100-metricas[1]*100))
print("Precisão de: %.2f%%" % (metricas[1]*100))
A predição é a etapa final do processamento de execução do protótipo, e é responsável por apresentar a classificação de uma ou mais imagens, baseado no aprendizado adquirido pela rede, na fase de treinamento
def predizer(model, imagens):
"""Esta função é responsável por realizar a predição
do conjunto de dados. Recebe como parametro o
modelo da rede, e retorna uma tupla contendo a
matriz de probabilidade e a matriz da classificação.
Args:
model (sequencial): modelo da rede neural
treinado.
imagens (list): lista contendo as imagens
para predizer a emoção
Returns:
np.array: matriz de probabilidade
np.array: matriz da classificação
"""
print('Predição da(s) imagem(ns)...')
m_probabilidade = model.predict(X_test, batch_size=32, verbose=1)
m_predicao = [np.argmax(prob) for prob in m_probabilidade]
print('Predição completa!')
print('Quantidade de imagens analisadas: ', len(m_predicao))
return m_probabilidade, m_predicao
y_probabilidade, predicted = predizer(loaded_model, X_test)
# Verificando a precisão por classe
# precision= A precisão é a razão onde é o número de positivos verdadeiros e o número de falsos positivos
# recall= O recall é a razão onde é o número de positivos verdadeiros e o número de falsos negativos
# f1-score= A média harmônica ponderada da precisão e recall
# support= O suporte é o número de ocorrências de cada classe verdade
print(classification_report(np.argmax(Y_test, axis=1), predicted, target_names=classes_emocoes))
Nesta etapa é ilustrado algumas imagens que foram preditas pela rede Deep-Emotive.
São selecionadas trinta imagens aleatórias e preditas, o resultado é plotado.
amosta = 30
fig = plt.figure(figsize=(16,16))
for i in range(amosta):
#plt.subplot(1, amosta, i+1)
# Seleciona uma imagem aleatoria
idx_img_aleatoria = random.randint(0, len(X_test[0]))
img_aleatoria = X_test[idx_img_aleatoria]
ax = fig.add_subplot(10,10,i+1)
# Visualiza a imagem escolhida aleatoriamente
plt.imshow(img_aleatoria.reshape(img_cols, img_rows), interpolation='nearest', cmap='gray')
# Visualiza o label
plt.text(0, 0, classes_emocoes[predicted[idx_img_aleatoria]], color='white',
bbox=dict(facecolor='black', alpha=1), fontsize=20)
plt.axis('off')
plt.xticks(np.array([]))
plt.yticks(np.array([]))
plt.tight_layout()
plt.show()
# Função para matriz de confusão da predição
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Matriz de confusão',
cmap=plt.cm.Blues):
"""
This function prints and plots the confusion matrix.
Normalization can be applied by setting `normalize=True`.
"""
if normalize:
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
im = plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar(im, fraction=0.046, pad=0.04)
#plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes)
plt.yticks(tick_marks, classes)
fmt = '.2f' if normalize else 'd'
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, format(cm[i, j], fmt),
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.tight_layout()
plt.ylabel('Base de teste')
plt.xlabel('Predições')
# Visualizando matriz de confusão da predição
#classes = ['alegria', 'desgosto', 'desprezo', 'medo', 'neutral', 'raiva', 'surpresa', 'tristeza']
# Precisa ter o mesmo formato
print('Verificando quantidade de imagens da predição: {}'.format(len(predicted)))
print('Verificando formato dos dados de testes: {}'.format(Y_test.shape))
cnf_matrix = confusion_matrix(np.argmax(Y_test, axis=1), predicted)
np.set_printoptions(precision=2)
# Visualizando a matriz de confusão sem normalização.
# mosta a quantidade de imagens classificadas para cada label
plt.figure(figsize=(7,7))
plot_confusion_matrix(cnf_matrix, classes=classes_emocoes,
title='Matriz de confusão')
# Visualizando a matriz de confusão com normalização.
# mosta a precisão para cada label classificado
plt.figure(figsize=(7,7))
plot_confusion_matrix(cnf_matrix, classes=classes_emocoes, normalize=True,
title='Matriz de confusão, probabilidade')
plt.show()
# Conferindo a distribuição novamente
# Verificando se a quantidade de amostra pode influenciar no aprendizado
visualiza_distribuicao(imagens)
Visualização das camadas intermediárias, que consiste em visualizar como os neurônios de cada mapa de caracterÃstica estão sendo ativados. Isto é realizado através da visualização da saÃda de cada camada convolucional da rede neural profunda.
# Listando as camadas da rede DNN
lista_camadas = OrderedDict()
for layer in model.layers[0:]:
lista_camadas[layer.name] = layer
print(layer.name)
def get_ativacoes(model, camada, input_img_data):
# Função tesorflow
ativacoes_out = K.function([model.layers[0].input, K.learning_phase()], [camada.output,])
# Pega as ativações da imagem
ativacoes = ativacoes_out((input_img_data, False))
return ativacoes
# Seleciona uma imagem aleatoria
idx_img_aleatoria = random.randint(0, X_test.shape[0])
input_img_data = X_test[idx_img_aleatoria].reshape(img_rows, img_cols)
plt.figure(figsize=(7,7))
plt.imshow(input_img_data, cmap="gray")
# Visualiza o label
plt.text(0, 0, classes_emocoes[predicted[idx_img_aleatoria]], color='white',
bbox=dict(facecolor='black', alpha=1), fontsize=20)
#plt.axis('off')
# Conferindo o shape
input_img_data = np.expand_dims(input_img_data, axis=0)
print('Input image shape:', input_img_data.shape)
# Formantado o Shape para tensor
print("Shape inicial:",input_img_data.shape)
# TensorFlow = ChannelLast
input_img_data = input_img_data.reshape((input_img_data.shape[0],) + shape).astype('float32')
print("Novo shape:",input_img_data.shape)
# Pegando as ativações da saÃda da primeira camada de convolucao
camada_nome = 'Bl01_Conv'# primeira camada
camada1 = lista_camadas[camada_nome]
ativacoes_camada1 = get_ativacoes(model, camada1, input_img_data)
# Visualizando o shape da primeira ativação
print(len(ativacoes_camada1))
print(np.shape(ativacoes_camada1)) # (1,1,largura,altura,nucleos) = tensorflow
# (1,1,nucloes,largura,altura) = theano
ativacao_camada_1 = ativacoes_camada1[0][0]
print(ativacao_camada_1.shape) # (1,largura,altura,nucleos) = tensorflow
# (1,nucloes,largura,altura) = theano
if K.image_dim_ordering() =='th':
ativacoes_camada1 = np.rollaxis((np.rollaxis(ativacao_camada_1,2,0)),2,0)
print('Theano: ',ativacao_camada_1.shape)
print('Tensorflow: ',ativacao_camada_1.shape)
# Quantidade de núcleos
print('Quantidade de núcleos na camada: ',camada1.filters)
Accent, Accent_r, Blues, Blues_r, BrBG, BrBG_r, BuGn, BuGn_r, BuPu, BuPu_r, CMRmap, CMRmap_r, Dark2, Dark2_r, GnBu, GnBu_r, Greens, Greens_r, Greys, Greys_r, OrRd, OrRd_r, Oranges, Oranges_r, PRGn, PRGn_r, Paired, Paired_r, Pastel1, Pastel1_r, Pastel2, Pastel2_r, PiYG, PiYG_r, PuBu, PuBuGn, PuBuGn_r, PuBu_r, PuOr, PuOr_r, PuRd, PuRd_r, Purples, Purples_r, RdBu, RdBu_r, RdGy, RdGy_r, RdPu, RdPu_r, RdYlBu, RdYlBu_r, RdYlGn, RdYlGn_r, Reds, Reds_r, Set1, Set1_r, Set2, Set2_r, Set3, Set3_r, Spectral, Spectral_r, Vega10, Vega10_r, Vega20, Vega20_r, Vega20b, Vega20b_r, Vega20c, Vega20c_r, Wistia, Wistia_r, YlGn, YlGnBu, YlGnBu_r, YlGn_r, YlOrBr, YlOrBr_r, YlOrRd, YlOrRd_r, afmhot, afmhot_r, autumn, autumn_r, binary, binary_r, bone, bone_r, brg, brg_r, bwr, bwr_r, cool, cool_r, coolwarm, coolwarm_r, copper, copper_r, cubehelix, cubehelix_r, flag, flag_r, gist_earth, gist_earth_r, gist_gray, gist_gray_r, gist_heat, gist_heat_r, gist_ncar, gist_ncar_r, gist_rainbow, gist_rainbow_r, gist_stern, gist_stern_r, gist_yarg, gist_yarg_r, gnuplot, gnuplot2, gnuplot2_r, gnuplot_r, gray, gray_r, hot, hot_r, hsv, hsv_r, inferno, inferno_r, jet, jet_r, magma, magma_r, nipy_spectral, nipy_spectral_r, ocean, ocean_r, pink, pink_r, plasma, plasma_r, prism, prism_r, rainbow, rainbow_r, seismic, seismic_r, spectral, spectral_r, spring, spring_r, summer, summer_r, tab10, tab10_r, tab20, tab20_r, tab20b, tab20b_r, tab20c, tab20c_r, terrain, terrain_r, viridis, viridis_r, winter, winter_r
# visualizando a ativação realizado pelos nucleos
idx_nucleo = 0 # primeiro núcleo
fig = plt.figure(figsize=(6,6))
plt.imshow(ativacao_camada_1[:,:,idx_nucleo], cmap='jet')
# Visualizando as ativações da imagem através das camadas convoluÃdas
# Visualizando as ativaçoes de todos núcleos
fig=plt.figure(figsize=(16,16))
plt.title("núcleos-layer-{}".format(layer))
subplot_num=int(np.ceil(np.sqrt(camada1.filters)))
for i in range(camada1.filters):
ax = fig.add_subplot(subplot_num, subplot_num, i+1)
# Algums mapas de cor: Paired, CMRmap_r, Accent, nipy_spectral, gnuplot, gnuplot2, hot_r, jet, ocean_r, viridis
ax.imshow(ativacao_camada_1[:,:,i],cmap='jet')
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.show()
# para salvar os nucloes em arquivo
fig.savefig("./util/deepemotive-nucleos-{}".format(camada1.name) + '.jpg')
# Pegando as ativações da saÃda da primeira camada de convolucao
camada_nome = 'Bl02_Conv' # segunda camada
camada2 = lista_camadas[camada_nome]
ativacoes_camada2 = get_ativacoes(model, camada2, input_img_data)
# Visualizando o shape da primeira ativação
print(len(ativacoes_camada2))
print(np.shape(ativacoes_camada2)) # (1,1,largura,altura,nucleos) = tensorflow
# (1,1,nucloes,largura,altura) = theano
ativacao_camada_2 = ativacoes_camada2[0][0]
print(ativacao_camada_2.shape) # (1,largura,altura,nucleos) = tensorflow
# (1,nucloes,largura,altura) = theano
if K.image_dim_ordering() =='th':
ativacoes_camada2 = np.rollaxis((np.rollaxis(ativacao_camada_2, 2, 0)), 2, 0)
print('Theano: ',ativacao_camada_2.shape)
print('Tensorflow: ',ativacao_camada_2.shape)
# Quantidade de núcleos
print('Quantidade de núcleos na camada: ',camada2.filters)
# visualizando a ativação realizado pelos nucleos
idx_nucleo = 0 # primeiro núcleo
fig = plt.figure(figsize=(6,6))
plt.imshow(ativacao_camada_2[:,:,idx_nucleo], cmap='jet')
# Visualizando as ativações da imagem através das camadas convoluÃdas
# Visualizando as ativaçoes de todos núcleos
fig=plt.figure(figsize=(16,16))
plt.title("núcleos-layer-{}".format(layer))
subplot_num=int(np.ceil(np.sqrt(camada2.filters)))
for i in range(camada2.filters):
ax = fig.add_subplot(subplot_num, subplot_num, i+1)
# Algums mapas de cor: Paired, CMRmap_r, Accent, nipy_spectral, gnuplot, gnuplot2, hot_r, jet, ocean_r, viridis
ax.imshow(ativacao_camada_2[:,:,i],cmap='jet')
plt.xticks([])
plt.yticks([])
#plt.tight_layout()
plt.show()
# para salvar os nucloes em arquivo
fig.savefig("./util/deepemotive-nucleos-{}".format(camada2.name) + '.jpg')
# Pegando as ativações da saÃda da primeira camada de convolucao
camada_nome = 'Bl03_Conv' # primeira camada
camada3 = lista_camadas[camada_nome]
ativacoes_camada3 = get_ativacoes(model, camada3, input_img_data)
# Visualizando o shape da primeira ativação
print(len(ativacoes_camada3))
print(np.shape(ativacoes_camada3)) # (1,1,largura,altura,nucleos) = tensorflow
# (1,1,nucloes,largura,altura) = theano
ativacao_camada_3 = ativacoes_camada3[0][0]
print(ativacao_camada_3.shape) # (1,largura,altura,nucleos) = tensorflow
# (1,nucloes,largura,altura) = theano
if K.image_dim_ordering() =='th':
ativacoes_camada3 = np.rollaxis((np.rollaxis(ativacao_camada_3, 2, 0)), 2, 0)
print('Theano: ',ativacao_camada_3.shape)
print('Tensorflow: ',ativacao_camada_3.shape)
# Quantidade de núcleos
print('Quantidade de núcleos na camada: ',camada3.filters)
# visualizando a ativação realizado pelos nucleos
idx_nucleo = 0 # primeiro núcleo
fig = plt.figure(figsize=(6,6))
plt.imshow(ativacao_camada_3[:,:,idx_nucleo], cmap='jet')
# Visualizando as ativações da imagem através das camadas convoluÃdas
# Visualizando as ativaçoes de todos núcleos
fig=plt.figure(figsize=(16,16))
plt.title("núcleos-layer-{}".format(layer))
subplot_num=int(np.ceil(np.sqrt(camada3.filters)))
for i in range(camada3.filters):
ax = fig.add_subplot(subplot_num, subplot_num, i+1)
# Algums mapas de cor: Paired, CMRmap_r, Accent, nipy_spectral, gnuplot, gnuplot2, hot_r, jet, ocean_r, viridis
ax.imshow(ativacao_camada_3[:,:,i],cmap='jet')
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.show()
# para salvar os nucloes em arquivo
fig.savefig("./util/deepemotive-nucleos-{}".format(camada3.name) + '.jpg')